﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using LFSRecord2.Misc;
using LFSRecord2.Model.Sound;
using LFSRecord2.Structures;

namespace LFSRecord2.View.Dialogs
{
    /// <summary>
    /// Interaction logic for ProjectConfigurationDialogBox.xaml
    /// </summary>
    public partial class ProjectConfigurationDialogBox : Window
    {
        List<Point> _availableResolutions = new List<Point>();

        public ProjectConfigurationDialogBox()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            LfsRecordProjectSettings pSettings = (LfsRecordProjectSettings)DataContext;

            // Populate hotkey textbox
            projectRecordStopHotkey.Text = KeyInterop.KeyFromVirtualKey(pSettings.RecordStopHotkey).ToString();

            // Create resolutions list
            DevicesInfo devInfo = new DevicesInfo();
            Collection<DeviceMode> mainDeviceModes;

            //double aspect;
            //double[] allowedAspects = new double[3];
            //allowedAspects[0] = 4.0d / 3.0d;
            //allowedAspects[1] = 16.0d / 9.0d;
            //allowedAspects[2] = 16.0d / 10.0d;
            string modeString;

            for (int a = 0; a < devInfo.Devices.Count; a++)
            {
                if ((devInfo.Devices[a].StateFlags & 4) == 0)
                    continue;
                //Debug.WriteLine(devInfo.Devices[a].DeviceID + " - " + devInfo.Devices[a].DeviceString + " - " + devInfo.Devices[a].DeviceKey + " - " + devInfo.Devices[a].DeviceName);

                mainDeviceModes = DevicesInfo.EnumModes(a);
                for (int b = 0; b < mainDeviceModes.Count; b++)
                {
                    if (mainDeviceModes[b].DMBitsPerPel != 32)
                        continue;

                    insertScreenResolution(new Point(mainDeviceModes[b].DMScreenWidth, mainDeviceModes[b].DMScreenHeight));

                    //aspect = mainDeviceModes[b].DMScreenWidth / (double)mainDeviceModes[b].DMScreenHeight;
                    //for (int c = 0; c < 3; c++)
                    //{
                    //    if (allowedAspects[c] == aspect)
                    //    {
                    //        insertScreenResolution(new Point(mainDeviceModes[b].DMScreenWidth, mainDeviceModes[b].DMScreenHeight));
                    //        break;
                    //    }
                    //}
                }

                break;
            }

            bool haveRes = false;
            for (int a = 0; a < _availableResolutions.Count; a++)
            {
                modeString = _availableResolutions[a].X + " * " + _availableResolutions[a].Y;
                ScreenResolutionComboBox.Items.Add(modeString);

                if (_availableResolutions[a].X == pSettings.RecordingWidth && _availableResolutions[a].Y == pSettings.RecordingHeight)
                {
                    ScreenResolutionComboBox.Text = modeString;
                    haveRes = true;
                }
            }
            
            if (!haveRes)
            {
                ScreenResolutionComboBox.Text = (string)ScreenResolutionComboBox.Items[0];
            }

            // Populate sound devices combobox
            WaveOutCaps currentCaps = WaveIO.DeviceCaps(pSettings.AudioOutputDevice);
            for (int a = 0; a < pSettings.AudioOutputDevices.Count; a++)
            {
                WaveOutCaps caps = pSettings.AudioOutputDevices[a];
                SoundDeviceComboBox.Items.Add(caps.szPname);
                if (currentCaps.szPname == caps.szPname)
                {
                    // Populate sample rate combobox according to selected device
                    populateSampleRateComboBox(pSettings, caps);
                }
            }
            SoundDeviceComboBox.SelectedIndex = pSettings.AudioOutputDevice + 1;

        }

        void populateSampleRateComboBox(LfsRecordProjectSettings pSettings, WaveOutCaps caps)
        {
            SampleRateComboBox.Items.Clear();
            int selectedIndex = 0;
            List<string> sampleRates = WaveIO.GetSampleRatesList(caps.dwFormats);
            for (int a = 0; a < sampleRates.Count; a++)
            {
                SampleRateComboBox.Items.Add(sampleRates[a]);
                if (sampleRates[a] == pSettings.SampleRate.ToString(CultureInfo.InvariantCulture))
                    selectedIndex = a;
            }
            SampleRateComboBox.SelectedIndex = selectedIndex;
        }

        void insertScreenResolution(Point sr)
        {
            if (_availableResolutions.Contains(sr))
                return;

            bool haveWidth = false;
            int srSum = (int)(sr.X + sr.Y);
            for (int a = 0; a < _availableResolutions.Count; a++)
            {
                if (sr.X < _availableResolutions[a].X)
                {
                    _availableResolutions.Insert(a, sr);
                    return;
                }
                else if (sr.X == _availableResolutions[a].X)
                {
                    haveWidth = true;
                }

                if (haveWidth && sr.Y < _availableResolutions[a].Y)
                {
                    _availableResolutions.Insert(a, sr);
                    return;
                }
            }

            _availableResolutions.Add(sr);
        }

        private void ScreenResolutionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            LfsRecordProjectSettings pSettings = (LfsRecordProjectSettings)DataContext;
            string modeString;

            for (int a = 0; a<_availableResolutions.Count; a++)
            {
                modeString = _availableResolutions[a].X + " * " + _availableResolutions[a].Y;
                if (modeString == (string)e.AddedItems[0])
                {
                    pSettings.RecordingWidth = (ushort)_availableResolutions[a].X;
                    pSettings.RecordingHeight = (ushort)_availableResolutions[a].Y;
                    break;
                }
            }
        }

        private void SoundDeviceComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count == 0)
                return;

            LfsRecordProjectSettings pSettings = (LfsRecordProjectSettings)DataContext;
            for (int a = 0; a < pSettings.AudioOutputDevices.Count; a++)
            {
                WaveOutCaps caps = pSettings.AudioOutputDevices[a];
                if (caps.szPname == (string)e.AddedItems[0])
                {
                    pSettings.AudioOutputDevice = a - 1;
                    //Debug.WriteLine("Have set new audio device - " + pSettings.AudioOutputDevices[a].szPname);

                    populateSampleRateComboBox(pSettings, caps);
                }
            }
        }

        private void SampleRateComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count == 0)
                return;

            LfsRecordProjectSettings pSettings = (LfsRecordProjectSettings)DataContext;
            uint newSampleRate = UInt32.Parse((string)e.AddedItems[0], CultureInfo.InvariantCulture);
            if (newSampleRate != pSettings.SampleRate)
            {
                pSettings.SampleRate = newSampleRate;
            }
        }

        void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            // Dialog box canceled
            this.DialogResult = false;
        }

        void okButton_Click(object sender, RoutedEventArgs e)
        {
            // Don't accept the dialog box if there is invalid data
            if (!IsValid(this)) return;

            // Dialog box accepted
            this.DialogResult = true;
        }

        // Validate all dependency objects in a window
        bool IsValid(DependencyObject node)
        {
            // Check if dependency object was passed
            if (node != null)
            {
                // Check if dependency object is valid.
                // NOTE: Validation.GetHasError works for controls that have validation rules attached 
                bool isValid = !Validation.GetHasError(node);
                if (!isValid)
                {
                    // If the dependency object is invalid, and it can receive the focus,
                    // set the focus
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }

            // If this dependency object is valid, check all child dependency objects
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {
                    // If a child dependency object is invalid, return false immediately,
                    // otherwise keep checking
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }

            // All dependency objects are valid
            return true;
        }

        /// <summary>
        /// Set the Hotkey value by previewing the KeyDown event of the textbox and handling the input here, instead of letting WPF write the input to the textbox.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void projectRecordStopHotkey_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
            if (e.SystemKey != Key.None)
                return;

            int vkCode = KeyInterop.VirtualKeyFromKey(e.Key);
            LfsRecordProjectSettings pSettings = (LfsRecordProjectSettings)DataContext;
            pSettings.RecordStopHotkey = (byte)vkCode;

            projectRecordStopHotkey.Text = e.Key.ToString();

            //Debug.WriteLine("Key pressed : " + ((int)e.Key) + " - " + vkCode + " - " + e.SystemKey);
        }

        private void projectFPSTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            byte fps = 0;

            if (byte.TryParse((string)((TextBox)sender).Text, out fps))
            {
                if ((100.0d / fps) % 1 > 0)
                {
                    FPSWarningLabel.Visibility = Visibility.Visible;
                    FPSWarningLabel2.Visibility = Visibility.Collapsed;
                }
                else if (fps  == 100)
                {
                    FPSWarningLabel.Visibility = Visibility.Collapsed;
                    FPSWarningLabel2.Visibility = Visibility.Visible;
                }
                else
                {
                    FPSWarningLabel.Visibility = Visibility.Collapsed;
                    FPSWarningLabel2.Visibility = Visibility.Collapsed;
                }
            }
        }
    }
}
